import BufferNode from '../entities/Buffer'
import Generator from '../entities/Generator'
import Sink from '../entities/Sink'
import Workstation from '../entities/Workstation'
import Canvas from '../../store/canvas/canvas'
import AssemblyStation from '../entities/AssemblyStation'
import DisassemblyStation from '../entities/DisassemblyStation'
import { dispatcher } from '../core/Dispatcher'
import BaseStation from '../entities/BaseStation'
import { getProductSize } from '../utils/ProductSize'
import Conveyor from '../entities/Conveyor'
import svgPathProperties from 'svg-path-properties'
import RandomFun from '../../store/randomFun/randomFun'
import AGV from '../entities/AGV'
import TrafficNetwork from '../../store/trafficNetwork/trafficNetwork'
import workerPool from '../entities/WorkerPool'
import BatchProcess from '../entities/BatchProcess'

export const modeling = (): void => {
  //拿到画布数据
  const canvasData = Canvas.getCanvas()
  const { nodes: nodeList, edges: edgeList } = canvasData
  //所有节点
  let tempObj: any = {}
  tempObj = {}

  //发生器节点
  const generatorList: Generator[] = []

  //需要初始化状态的节点
  const initNodeStatusList: BaseStation[] = []

  //构建每个模型
  nodeList.forEach((node) => {
    const type = node.type
    const { x, y, width, height } = node
    if (type === 'produce') {
      const { width: productWidth, height: productHeight } = getProductSize(node.id)
      //判断间隔是固定值还是随机函数
      let interval = 0 as number | string
      const type = node.simData.produce!.interval.type

      if (type === 'fixed') {
        interval = Number(node.simData.produce!.interval.fixed)
      } else {
        const randomId = node.simData.produce!.interval.random
        const random = RandomFun.getRandomFunById(randomId)
        if (!random) {
          throw new Error('随机函数不存在')
        } else {
          interval = random.funtionCode
        }
      }

      const data = new Generator(
        node.id,
        node.name,
        x,
        y,
        width,
        height,
        interval,
        Number(node.simData.produce!.quantity),
        node.simData.produce?.selfCirculation,
        productWidth,
        productHeight
      )
      tempObj[node.id] = data
      generatorList.push(data)
    } else if (type === 'process') {
      //判断间隔是固定值还是随机函数
      let processTime = 0 as number | string
      const type = node.simData.process!.processTime.type

      if (type === 'fixed') {
        processTime = Number(node.simData.process!.processTime.fixed)
      } else {
        const randomId = node.simData.process!.processTime.random
        const random = RandomFun.getRandomFunById(randomId)
        if (!random) {
          throw new Error('随机函数不存在')
        } else {
          processTime = random.funtionCode
        }
      }

      const data = new Workstation(
        node.id,
        node.name,
        x,
        y,
        width,
        height,
        processTime,
        Number(node.simData.process!.defectiveRate),
        Number(node.simData.process!.failureRate)
      )
      tempObj[node.id] = data
      initNodeStatusList.push(data)
    } else if (type === 'batchProcess') {
      const data = new BatchProcess(
        node.id,
        node.name,
        x,
        y,
        width,
        height,
        Number(node.simData.batchProcess!.batchQuantity),
        Number(node.simData.batchProcess!.processTime),
        node.simData.batchProcess!.animationDirection
      )
      tempObj[node.id] = data
      dispatcher.registerSpecialStation(data)
    } else if (type === 'buffer') {
      const data = new BufferNode(
        node.id,
        node.name,
        x,
        y,
        width,
        height,
        Number(node.simData.buffer!.capacity)
      )
      tempObj[node.id] = data
      dispatcher.registerSpecialStation(data)
    } else if (type === 'absorb') {
      const data = new Sink(node.id, node.name, x, y, width, height)
      tempObj[node.id] = data
      dispatcher.registerSpecialStation(data)
    } else if (type === 'assembly') {
      const inputPort = node.simData.assemble?.inputPorts || {}
      const time = node.simData.assemble?.assembleTime || 0
      const { width: productWidth, height: productHeight } = getProductSize(node.id)
      const data = new AssemblyStation(
        node.id,
        node.name,
        x,
        y,
        width,
        height,
        inputPort,
        Number(time),
        productWidth,
        productHeight
      )
      tempObj[node.id] = data
      initNodeStatusList.push(data)
    } else if (type === 'disassemble') {
      const time = node.simData.disassemble?.disassembleTime || 0
      const quantity = node.simData.disassemble?.quantity || 0
      const { width: productWidth, height: productHeight } = getProductSize(node.id)
      const data = new DisassemblyStation(
        node.id,
        node.name,
        x,
        y,
        width,
        height,
        Number(time),
        Number(quantity),
        productWidth,
        productHeight
      )
      tempObj[node.id] = data
      initNodeStatusList.push(data)
    } else if (type === 'AGV') {
      const data = new AGV(
        node.id,
        node.name,
        x,
        y,
        width,
        height,
        Number(node.simData.agv?.speed),
        Number(node.simData.agv?.capacity)
      )
      //如果agv绑定了交通网络，则需要初始化位置和点位
      if (node.simData.agv?.enableTraffic) {
        const item = TrafficNetwork.getAdjacentPoints([x, y])
        if (item) {
          const position = TrafficNetwork.getPositionById(item.id)
          data.initTrafficPoint(item.id, position)
        }
      }
      tempObj[node.id] = data
      dispatcher.registerSpecialStation(data)
    } else if (type === 'workerPool') {
      const data = new workerPool(
        node.id,
        node.name,
        node.x,
        node.y,
        Number(node.simData.workerPool?.workerNum),
        Number(node.simData.workerPool?.workerSpeed),
        Number(node.simData.workerPool?.maintenanceTime),
        node.simData.workerPool?.associatedDevices || []
      )
      dispatcher.registerWorkerPool(data)
    }
  })
  //构建特殊模型
  edgeList.forEach((edge) => {
    if (edge.shape === 'conveyor-belt') {
      const svgProperties = new svgPathProperties.svgPathProperties(edge.simData!.path!)
      const length = svgProperties.getTotalLength()

      if (length === 0) {
        new Error('传送带长度不能为 0')
      }
      const data = new Conveyor(
        edge.id,
        edge.name,
        edge.simData!.path!,
        edge.simData!.belt!.speed,
        length
      )
      tempObj[edge.id] = data
      dispatcher.registerSpecialStation(data)
    }
  })

  //连接关系
  let downstreamConnnection: any = {}
  downstreamConnnection = {}
  let upstreamConnnection: any = {}
  upstreamConnnection = {}
  edgeList.forEach((edge) => {
    if (edge.shape === 'ordinary-edge') {
      const targetId = edge.targetId
      const sourceId = edge.sourceId
      if (typeof targetId !== 'string' || typeof sourceId !== 'string') return
      let targetNode = tempObj[targetId]
      const sourceNode = tempObj[sourceId]

      //判断是否是搬运流线体
      if (edge.simData?.isTransport) {
        const transportId = edge.simData.transportId
        if (transportId) {
          const transport = tempObj[transportId]
          transport.setMapping(sourceNode, targetNode)
          targetNode = transport

          if (downstreamConnnection[sourceId]) {
            downstreamConnnection[sourceId].push(targetNode)
          } else {
            downstreamConnnection[sourceId] = [targetNode]
          }
        }
      } else {
        if (downstreamConnnection[sourceId]) {
          downstreamConnnection[sourceId].push(targetNode)
        } else {
          downstreamConnnection[sourceId] = [targetNode]
        }
        if (upstreamConnnection[targetId]) {
          upstreamConnnection[targetId].push(sourceNode)
        } else {
          upstreamConnnection[targetId] = [sourceNode]
        }
      }
    }
  })
  for (const key in downstreamConnnection) {
    console.log(key)
    tempObj[key].setNextStations(downstreamConnnection[key])
    tempObj[key].setPrevStations(upstreamConnnection[key])
  }

  //初始化状态
  dispatcher.registerIdleStation(initNodeStatusList)

  //开启工人池
  const workerPoolList = dispatcher.workerPoolList
  workerPoolList.forEach((workerPool) => {
    workerPool.initManualStation()
  })

  //开启发生器
  generatorList.forEach((generator) => {
    generator.start()
  })
}
